package com.zone.infrastructure.persistent.repository;

import com.google.gson.Gson;
import com.zone.domain.award.event.UserWinAwardEvent;
import com.zone.domain.award.model.aggregate.UserAwardRecordAggregate;
import com.zone.domain.award.model.aggregate.UserCreditAggregate;
import com.zone.domain.award.model.entity.AwardEntity;
import com.zone.domain.award.model.entity.UserAwardRecordEntity;
import com.zone.domain.award.model.entity.UserCreditAccountEntity;
import com.zone.domain.award.model.valobj.AwardStateEnum;
import com.zone.domain.award.repository.IAwardRepository;
import com.zone.domain.task.model.entity.TaskEntity;
import com.zone.domain.task.model.valobj.TaskState;
import com.zone.infrastructure.event.MessageProduct;
import com.zone.infrastructure.persistent.dao.*;
import com.zone.infrastructure.persistent.po.Award;
import com.zone.infrastructure.persistent.po.Task;
import com.zone.infrastructure.persistent.po.UserAwardRecord;
import com.zone.infrastructure.persistent.po.UserCreditAccount;
import com.zone.infrastructure.persistent.redis.IRedisService;
import com.zone.types.common.Constants;
import com.zone.types.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author: zongzi
 * @description: 奖品相关用户操作
 * @date: 2025/2/22
 */
@Slf4j
@Service
public class AwardRepository implements IAwardRepository {
    @Autowired
    private IUserAwardRecordDao userAwardRecordDao;
    @Autowired
    private ITaskDao taskDao;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private MessageProduct messageProduct;
    /** 消息主题 */
    @Value("${spring.rabbitmq.topic.user_win_award}")
    private String topic;
    @Autowired
    private IUserRaffleOrderDao userRaffleOrderDao;
    @Autowired
    private IAwardDao awardDao;
    @Autowired
    private IUserCreditAccountDao userCreditAccountDao;
    @Autowired
    private IRedisService redisService;

    @Override
    public void saveUserAwardRecord(UserAwardRecordAggregate userAwardRecordAggregate) {
        // 用户中奖记录
        UserAwardRecordEntity userAwardRecordEntity = userAwardRecordAggregate.getUserAwardRecordEntity();
        UserAwardRecord userAwardRecord = new UserAwardRecord();
        userAwardRecord.setUserId(userAwardRecordEntity.getUserId());
        userAwardRecord.setActivityId(userAwardRecordEntity.getActivityId());
        userAwardRecord.setStrategyId(userAwardRecordEntity.getStrategyId());
        userAwardRecord.setOrderId(userAwardRecordEntity.getOrderId());
        userAwardRecord.setAwardId(userAwardRecordEntity.getAwardId());
        userAwardRecord.setAwardTitle(userAwardRecordEntity.getAwardTitle());
        userAwardRecord.setAwardTime(userAwardRecordEntity.getAwardTime());
        userAwardRecord.setAwardState(userAwardRecordEntity.getAwardState().getCode());
        userAwardRecord.setAwardConfig(userAwardRecordEntity.getAwardConfig());
        // 消息发送任务
        TaskEntity taskEntity = userAwardRecordAggregate.getTaskEntity();
        Task task = new Task();
        task.setUserId(taskEntity.getUserId());
        task.setTopic(taskEntity.getTopic());
        task.setMessageId(taskEntity.getMessageId());
        task.setMessage(taskEntity.getMessage());
        task.setState(taskEntity.getState().getCode());
        transactionTemplate.execute(status -> {
            try {
                // 保存用户中奖记录
                userAwardRecordDao.insert(userAwardRecord);
                // 保存task
                taskDao.insert(task);
                // 更新用户参与单为已使用
                int count = userRaffleOrderDao.updateState2Used(userAwardRecordEntity.getUserId(), userAwardRecordEntity.getActivityId());
                if (1 != count) {
                    throw new BizException(String.format("更新用户参与单状态为”已使用失败, userId = %s, activityId = %s", userAwardRecordEntity.getUserId(), userAwardRecordEntity.getActivityId()));
                }
                return 1;
            } catch (Exception e) {
                status.setRollbackOnly();
                throw e;
            }
        });
        try {
            // 发送mq
            Gson gson = new Gson();
            UserWinAwardEvent userWinAwardEvent = gson.fromJson(taskEntity.getMessage(), UserWinAwardEvent.class);
            messageProduct.sendMessage(topic, userWinAwardEvent);
            // 更新task状态
            task.setState(TaskState.COMPLETED.getCode());
            taskDao.updateStateByMessageId(task);
        } catch (Exception e) {
            log.error("发送用户中间记录消息失败", e);
            // 更新task状态
            task.setState(TaskState.FAIL.getCode());
            taskDao.updateStateByMessageId(task);
        }
    }

    @Override
    public AwardEntity queryAward(Integer awardId) {
        Award award = awardDao.getAward(awardId);
        return Award.convert2Entity(award);
    }

    @Override
    public void saveUserCreditAccount(UserCreditAggregate userCreditAggregate) {
        // 用户积分账户
        UserCreditAccountEntity userCreditAccountEntity = userCreditAggregate.getUserCreditAccount();
        UserCreditAccount userCreditAccount = new UserCreditAccount();
        userCreditAccount.setUserId(userCreditAccountEntity.getUserId());
        userCreditAccount.setTotalAmount(userCreditAccountEntity.getTotalAmount());
        userCreditAccount.setAvailableAmount(userCreditAccountEntity.getAvailableAmount());
        userCreditAccount.setAccountStatus(userCreditAccountEntity.getAccountStatus().getCode());

        String lockKey = Constants.RedisKey.generate(Constants.RedisKey.USER_CREDIT_ACCOUNT_LOCK, userCreditAccountEntity.getUserId());
        RLock lock = redisService.getLock(lockKey);
        try {
            lock.lock(3, TimeUnit.SECONDS);
            transactionTemplate.execute(status -> {
                try {
                    // 更新用户积分账户
                    UserCreditAccount existedCreditAccount = userCreditAccountDao.queryUserCreditAccount(userCreditAccountEntity.getUserId());
                    if (Objects.isNull(existedCreditAccount)) {
                        userCreditAccountDao.insert(userCreditAccount);
                    } else {
                        userCreditAccountDao.addAmount(userCreditAccount);
                    }
                    // 更新用户中单订单状态
                    UserAwardRecordEntity userAwardRecordEntity = userCreditAggregate.getUserAwardRecord();
                    userAwardRecordDao.updateStates(userAwardRecordEntity.getUserId(), userAwardRecordEntity.getOrderId(), userAwardRecordEntity.getAwardState().getCode());
                    return 1;
                } catch (Exception e) {
                    status.setRollbackOnly();
                    throw e;
                }
            });
        } finally {
            lock.unlock();
        }
    }

    @Override
    public UserAwardRecordEntity queryUserAwardRecord(String userId, String orderId) {
        UserAwardRecord userAwardRecord = userAwardRecordDao.queryUserAwardRecord(userId, orderId);
        if (Objects.isNull(userAwardRecord)) {
            return null;
        }
        UserAwardRecordEntity userAwardRecordEntity = new UserAwardRecordEntity();
        userAwardRecordEntity.setUserId(userAwardRecord.getUserId());
        userAwardRecordEntity.setActivityId(userAwardRecord.getActivityId());
        userAwardRecordEntity.setStrategyId(userAwardRecord.getStrategyId());
        userAwardRecordEntity.setOrderId(userAwardRecord.getOrderId());
        userAwardRecordEntity.setAwardId(userAwardRecord.getAwardId());
        userAwardRecordEntity.setAwardTitle(userAwardRecord.getAwardTitle());
        userAwardRecordEntity.setAwardTime(userAwardRecord.getAwardTime());
        userAwardRecordEntity.setAwardState(AwardStateEnum.valueOf(userAwardRecord.getAwardState()));
        userAwardRecordEntity.setAwardConfig(userAwardRecord.getAwardConfig());
        return userAwardRecordEntity;
    }
}
